from functools import wraps

import jwt
from rest_framework.response import Response
from rest_framework_simplejwt.backends import TokenBackend
from system.models import User, Menu, RoleMenu, Role, UserRole, Department


def permission_required(perms_list):
    """
    权限验证装饰器
    
    :param perms_list: 权限标识列表，如 ["sys:user:add", "sys:user:edit"]
    :return: 如果用户拥有所有指定权限则允许访问，否则返回无权限提示
    """

    def decorator(view_func):
        @wraps(view_func)
        def wrapper(self, request, *args, **kwargs):
            # 1. 从 Authorization 头中获取 token
            auth_header = request.headers.get("Authorization")
            if not auth_header or not auth_header.startswith("Bearer "):
                return Response({"code": "A0301", "msg": "未授权，请先登录"}, status=401)

            token = auth_header.split()[1]

            # 2. 解析 token 获取用户 ID
            token_backend = TokenBackend(algorithm="HS256")
            try:
                token_data = token_backend.decode(token, verify=False)
                user_id = token_data.get("user_id")
                if not user_id:
                    return Response({"code": "A0302", "msg": "无效的令牌"}, status=401)
            except jwt.DecodeError:
                return Response({"code": "A0303", "msg": "令牌解析失败"}, status=401)

            # 3. 获取用户信息和用户的角色列表
            try:
                user = User.objects.get(id=user_id)
                if not user.is_active or user.is_deleted == 1:
                    return Response({"code": "A0304", "msg": "用户已禁用或删除"}, status=403)

                # 如果是root用户，直接放行，不需要验证权限
                if user.is_superuser:
                    return view_func(self, request, *args, **kwargs)

                # 获取用户角色 ID 列表
                role_ids = user.roles.values_list('id', flat=True)
                if not role_ids:
                    return Response({"code": "A0305", "msg": "用户未分配任何角色"}, status=403)
            except User.DoesNotExist:
                return Response({"code": "A0306", "msg": "用户不存在"}, status=403)

            # 如果无需权限，直接放行
            if not perms_list:
                return view_func(self, request, *args, **kwargs)

            # 4. 根据权限标识查找对应的菜单 ID
            menu_ids = []
            for perm in perms_list:
                try:
                    menu = Menu.objects.get(perm=perm)
                    menu_ids.append(menu.id)
                except Menu.DoesNotExist:
                    # 如果权限标识不存在，记录日志但继续检查其他权限
                    continue

            if not menu_ids:
                return Response({"code": "A0307", "msg": "请求的权限不存在"}, status=403)

            # 5. 检查用户角色是否拥有所有需要的菜单权限
            # 查询角色-菜单关联表，看角色是否拥有这些菜单权限

            all_permissions_granted = True

            for menu_id in menu_ids:
                # 检查是否存在角色-菜单关联
                role_menu_exists = RoleMenu.objects.filter(
                    role_id__in=role_ids,
                    menu_id=menu_id
                ).exists()

                if not role_menu_exists:
                    all_permissions_granted = False
                    break

            if all_permissions_granted:
                # 用户拥有所有需要的权限，允许访问
                return view_func(self, request, *args, **kwargs)
            else:
                # 用户缺少至少一项所需权限，拒绝访问
                return Response({
                    "code": "A0310",
                    "msg": "权限不足，无法执行此操作"
                }, status=403)

        return wrapper

    return decorator


"""
数据权限验证函数
"""


def data_permission_required(token, operation=None, target_user_id=None):
    """
    数据权限验证函数
    Role模型中的data_scope字段说明：1-所有数据 2-本部门及子部门数据 3-本部门数据 4-本人数据

    支持两种模式:
    1. 操作权限验证模式: 验证当前用户是否有权限操作指定用户的数据
       传入参数: token, operation(add/update/delete中的一个), target_user_id(被操作的用户ID)
       返回值: True/False 表示是否有权限
       
    2. 查询范围模式: 获取当前用户可以查看的用户ID范围
       传入参数: token, operation="select"
       返回值: "all" 或 用户ID列表
    
    :param token: 用户令牌
    :param operation: 操作类型，可以是"add", "update", "delete", "select"
    :param target_user_id: 被操作的用户ID，仅在操作权限验证模式下需要
    :return: 根据模式返回不同的结果
    :raises: ValidationError 当权限验证失败时
    """
    from rest_framework.exceptions import ValidationError

    # 1. 解析token获取用户ID
    try:
        # 去除Bearer
        if token.startswith('Bearer '):
            token = token.split(' ')[1]
        token_backend = TokenBackend(algorithm="HS256")
        token_data = token_backend.decode(token, verify=False)
        current_user_id = token_data.get("user_id")
        if not current_user_id:
            raise ValidationError({"code": "A0320", "msg": "数据权限验证错误：无效的用户ID"})
    except Exception as e:
        raise ValidationError({"code": "A0321", "msg": f"数据权限验证错误：令牌解析失败 - {str(e)}"})

    # 2. 查询当前用户信息
    try:
        current_user = User.objects.get(id=current_user_id)

        # 检查用户状态
        if current_user.is_deleted == 1:
            raise ValidationError({"code": "A0326", "msg": "数据权限验证错误：用户已删除"})

        if current_user.status == 0:
            raise ValidationError({"code": "A0327", "msg": "数据权限验证错误：用户已禁用"})

        # 3. 如果是超级管理员，直接返回最高权限
        if current_user.is_superuser:
            # 超级管理员在查询模式下返回"all"
            if operation == "select":
                return "all"
            # 超级管理员在操作验证模式下返回True
            return True

        # 4. 查询用户所有角色的data_scope
        user_roles = UserRole.objects.filter(user_id=current_user_id)
        if not user_roles.exists():
            raise ValidationError({"code": "A0322", "msg": "数据权限验证错误：用户未分配任何角色"})

        # 5. 获取所有角色ID
        role_ids = [ur.role_id for ur in user_roles]

        # 6. 查询这些角色的data_scope
        roles = Role.objects.filter(id__in=role_ids)
        if not roles.exists():
            raise ValidationError({"code": "A0323", "msg": "数据权限验证错误：角色不存在"})

        # 7. 获取最小的data_scope值（最高权限）
        data_scopes = [role.data_scope for role in roles if role.data_scope is not None]
        if not data_scopes:
            raise ValidationError({"code": "A0324", "msg": "数据权限验证错误：角色未配置数据权限"})

        min_data_scope = max(1, min(min(data_scopes), 4))

        # 8. 根据data_scope和操作类型进行权限验证
        if operation == "select":
            # 查询模式，返回可查看的用户ID范围
            return get_viewable_user_ids(current_user, min_data_scope)
        elif operation in ["add", "update", "delete"]:
            # 操作验证模式，验证是否有权限操作目标用户
            if target_user_id is None:
                raise ValidationError({"code": "A0328", "msg": "数据权限验证错误：未提供目标用户ID"})

            return has_permission_to_operation(current_user, min_data_scope, target_user_id)
        else:
            raise ValidationError({"code": "A0330", "msg": f"数据权限验证错误：不支持的操作类型 {operation}"})

    except User.DoesNotExist:
        raise ValidationError({"code": "A0325", "msg": "数据权限验证错误：用户不存在"})
    except ValidationError:
        # 重新抛出ValidationError异常
        raise
    except Exception as e:
        # 其他异常情况，抛出ValidationError
        raise ValidationError({"code": "A0329", "msg": f"数据权限验证错误：{str(e)}"})


def get_department_and_children_ids(dept_id):
    """
    递归获取部门及其所有子部门ID
    
    :param dept_id: 部门ID
    :return: 部门及其所有子部门ID的列表
    """
    if dept_id is None:
        return []

    # 初始化结果列表，包含当前部门ID
    result = [dept_id]

    # 查找所有子部门
    children = Department.objects.filter(parent_id=dept_id, is_deleted=0)

    # 递归获取每个子部门的子部门
    for child in children:
        result.extend(get_department_and_children_ids(child.id))

    return result


def get_department_user_ids(dept_ids):
    """
    获取指定部门列表中的所有用户ID
    
    :param dept_ids: 部门ID列表
    :return: 用户ID列表
    """
    users = User.objects.filter(dept_id__in=dept_ids, is_deleted=0, status=1)
    return [user.id for user in users]


def get_viewable_user_ids(current_user, data_scope):
    """
    获取当前用户可以查看的用户ID范围
    
    :param current_user: 当前用户对象
    :param data_scope: 数据权限级别
    :return: "all" 或 用户ID列表
    """
    # 1. 所有数据权限
    if data_scope == 1:
        return "all"

    # 2. 本部门及子部门数据权限
    elif data_scope == 2:
        if current_user.dept_id:
            # 获取当前用户部门及所有子部门
            dept_ids = get_department_and_children_ids(current_user.dept_id)
            # 获取这些部门的所有用户ID
            return get_department_user_ids(dept_ids)
        else:
            # 用户没有部门，只能看自己的数据
            return [current_user.id]

    # 3. 本部门数据权限
    elif data_scope == 3:
        if current_user.dept_id:
            # 获取当前用户部门的所有用户ID
            return get_department_user_ids([current_user.dept_id])
        else:
            # 用户没有部门，只能看自己的数据
            return [current_user.id]

    # 4. 仅本人数据权限
    else:  # data_scope == 4
        return [current_user.id]


def has_permission_to_operation(current_user, data_scope, target_user_id):
    """
    验证当前用户是否有权限操作目标用户的数据
    
    :param current_user: 当前用户对象
    :param data_scope: 数据权限级别
    :param target_user_id: 被操作的用户ID
    :return: True或False
    """
    # 如果目标用户就是当前用户，总是允许操作
    if int(current_user.id) == int(target_user_id):
        return True

    try:
        # 获取目标用户信息
        target_user = User.objects.get(id=target_user_id)

        # 1. 所有数据权限
        if data_scope == 1:
            return True

        # 2. 本部门及子部门数据权限
        elif data_scope == 2:
            if current_user.dept_id:
                # 获取当前用户部门及所有子部门
                dept_ids = get_department_and_children_ids(current_user.dept_id)
                # 检查目标用户的部门是否在可访问的部门列表中
                return target_user.dept_id in dept_ids
            else:
                # 用户没有部门，只能操作自己的数据
                return False

        # 3. 本部门数据权限
        elif data_scope == 3:
            if current_user.dept_id and target_user.dept_id:
                # 检查目标用户是否在同一部门
                return current_user.dept_id == target_user.dept_id
            else:
                # 如果任一 用户没有部门，不允许操作
                return False

        # 4. 仅本人数据权限
        else:  # data_scope == 4
            # 仅本人数据权限下，不能操作其他用户的数据
            return False

    except User.DoesNotExist:
        # 目标用户不存在，不允许操作
        return False
